use hex;
use sha1::{Digest, Sha1};
use std::{fmt, str};
use uuid::Uuid;
use bytes::{BytesMut, BufMut, LittleEndian};
use std::any::TypeId;
use std::hash::{Hash,Hasher};
use std::io::{Write,Result};
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Sha1str {
    sha1: [u8; 40],
}
#[derive(Clone, Debug, Default)]
pub struct MySha1 {
    pub state:Sha1
}

impl Hasher for MySha1 {
    fn finish(&self) -> u64 {
        0
    }
    fn write(&mut self, bytes: &[u8]) {
        self.state.write(bytes);
    } 
}

impl fmt::Display for Sha1str {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = str::from_utf8(&self.sha1).unwrap();
        write!(f, "{}", s)
    }
}

impl Default for Sha1str {
    fn default() -> Self { Self { sha1: [0x30_u8; 40] } }
}

impl Sha1str {
    fn new(c: &[u8]) -> Self {
        let mut hasher = MySha1::default();
        hasher.write(c);
        let mut r = Sha1str::default();
        hex::encode_to_slice(hasher.state.finalize(), r.sha1.as_mut());
        r
    }
    pub fn of<T:Hash>(t:&T) -> Self {
        let mut hasher = MySha1::default();
        t.hash::<MySha1>(&mut hasher);
        let mut r = Sha1str::default();
        hex::encode_to_slice(hasher.state.finalize(), r.sha1.as_mut());
        r
    }
    // pub fn type_key<T>(name :&str) -> Self { 
    //     let mut buf = BytesMut::with_capacity(1024);
    //     buf.put_u64::<LittleEndian>(std::intrinsics::type_id::<T>());
    //     buf.write(name.as_bytes());
    //     let b = buf.take();
    //     let mut hasher = Sha1::new();
    //     hasher.update(b);
    //     let mut r = Sha1str::default();
    //     hex::encode_to_slice(hasher.digest().bytes(), r.sha1.as_mut());
    //     r       
    // }
    // pub fn type_id_key(tid:u64, name :&str) -> Self { 
    //     let mut buf = BytesMut::with_capacity(1024);
    //     buf.put_u64::<LittleEndian>(tid);
    //     buf.write(name.as_bytes());
    //     let b = buf.take();
    //     let mut hasher = sha1::Sha1::new();
    //     hasher.update(b);
    //     let mut r = Sha1str::default();
    //     hex::encode_to_slice(hasher.digest().bytes(), r.sha1.as_mut());
    //     r       
    // }
    pub fn key(&self) -> Ukey {Ukey::str2key(&self.sha1)}
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Ukey {
    id:Uuid,
}

impl Ukey {
    pub fn usrtos_ns() -> Uuid {
        Uuid::parse_str("8ea09e05-fd67-5949-a9ab-e722a3dae01c").unwrap()
    }
    pub fn signture(s: &[u8], l: usize) -> Sha1str {
        Sha1str::new(&s[..l])
    }
    pub fn str2key(buf: &[u8]) -> Self {
        let ns = Ukey::usrtos_ns();
        let u = Uuid::new_v5(&ns, buf);
        Self{id:u}
    }
    pub fn to_string(&self) -> String {
        self.id.to_string()
    }
    // pub fn type_key<T>(name: &str) -> Self {
    //     Sha1str::type_key::<T>(name).key()
    // }
    pub fn of<T:Hash>(t:&T) -> Self {
        Sha1str::of::<T>(t).key()
    }
    // pub fn type_id_key(tid:u64,name: &str) -> Self {
    //     Sha1str::type_id_key(tid,name).key()
    // }
}

impl fmt::Display for Ukey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.id)
    }
}

impl Default for Ukey {
    fn default() -> Self { Self{id:Ukey::usrtos_ns()} }
}
